package top.jfunc.common.utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 枚举类的工具方法
 */
public class EnumUtil {
	public static final char IDENTIFIER_YES = '1';
	public static final char IDENTIFIER_NO  = '0';

	private EnumUtil() {
	}

	/**
	 * 每个业务对应一个位置，从0开始，为1的表示匹配
	 * 1001001....
	 * 表示0号位置的业务要匹配，1号位置的不要匹配，2号位置的不要匹配，3号位置的要匹配，4号位置的不要匹配，5号位置的不要匹配，6号位置的要匹配...
	 */
	public static <E extends Enum<E>> String matchIdentifier(E[] enums) {
		return matchIdentifier(Arrays.asList(enums));
	}
	public static <E extends Enum<E>> String matchIdentifier(E e) {
		return matchIdentifier(Collections.singletonList(e));
	}

	public static <E extends Enum<E>> String matchIdentifier(Collection<E> enums) {
		List<E> enumList = enums.stream().sorted(Comparator.comparingInt(Enum::ordinal)).collect(Collectors.toList());
		//最靠后的那一个的origin最大
		E maxEnum = enumList.get(enumList.size() - 1);
		int length = maxEnum.ordinal() + 1;
		StringBuilder builder = new StringBuilder(length);
		for (int i = 0; i < length; i++) {
			builder.append(IDENTIFIER_NO);
		}
		for (Enum<E> e : enumList) {
			builder.setCharAt(e.ordinal(), IDENTIFIER_YES);
		}
		return builder.toString();
	}

	/**
	 * 获取某一个枚举类全量对象对应的标识字符串，意义跟调用枚举的values()一致
	 * @param eClass 枚举类
	 * @param <E> 枚举
	 * @return 某一个枚举的所有对象的标识字符串
	 */
	public static <E extends Enum<E>> String matchIdentifier(Class<E> eClass){
		StringBuilder builder = matchIdentifierBuilder(eClass);
		return builder.toString();
	}

	/**
	 * 提供根据一个枚举类和
	 * @param eClass 枚举类
	 * @param excludeEnums 排除哪些枚举
	 * @param <E> 枚举泛型
	 */
	public static <E extends Enum<E>> String matchIdentifier(Class<E> eClass, E[] excludeEnums){
		StringBuilder builder = matchIdentifierBuilder(eClass);
		Arrays.stream(excludeEnums).forEach(e -> builder.setCharAt(e.ordinal(), IDENTIFIER_NO));
		return builder.toString();
	}

	private static <E extends Enum<E>> StringBuilder matchIdentifierBuilder(Class<E> eClass) {
		E[] enumConstants = eClass.getEnumConstants();
		StringBuilder builder = new StringBuilder(enumConstants.length);
		for (int i = 0; i < enumConstants.length; i++) {
			builder.append(IDENTIFIER_YES);
		}
		return builder;
	}

	/**
	 * 给定一个标识字符串，判断某个业务是否匹配上。即判定对应位置是否为1
	 * @param businessIdentifier 标识符
	 * @param e 特定的一个枚举值
	 * @param <E> 枚举
	 */
	public static <E extends Enum<E>> boolean matches(String businessIdentifier, E e) {
		int ordinal = e.ordinal();
		return businessIdentifier.length() > ordinal
				&& businessIdentifier.charAt(ordinal) == IDENTIFIER_YES;
	}
	public static <E extends Enum<E>> boolean matches(String businessIdentifier, E[] enums) {
		for (E e : enums) {
			if (!matches(businessIdentifier, e)) {
				return false;
			}
		}

		return true;
	}

	/**
	 * 给定一串标识符，看是否执行
	 * @param businesses 标识符
	 * @param enums 业务枚举，一般都是枚举类的values()方法
	 * @param consumer 匹配上了做什么
	 * @param <E> 枚举
	 */
	public static <E extends Enum<E>> void doIfMatch(String businesses,
													 E[] enums,
													 Consumer<E> consumer) {
		for (E e : enums) {
			//某一位上为1，表示要执行同步，如此可以非常灵活优雅地控制同步哪些订单，不同步哪些订单
			if(EnumUtil.matches(businesses, e)){
				consumer.accept(e);
			}
		}
	}


	/**
	 * 根据枚举的某些特点确定是哪个
	 * @param enumClass 枚举的类
	 * @param predicate 判断方法
	 * @param valueConverter 返回枚举经过处理后的值
	 * @param valueIfNotFound 如果未匹配成功返回什么
	 * @return 某个枚举值
	 * @param <E> 枚举
	 * @param <V> 返回的value值
	 */
	public static <E extends Enum<E>, V> V from(Class<E> enumClass, Predicate<E> predicate, Function<E,V> valueConverter, V valueIfNotFound) {
		E[] enumConstants = enumClass.getEnumConstants();
		for (E e : enumConstants) {
            if (predicate.test(e)) {
                return valueConverter.apply(e);
            }
		}

		return valueIfNotFound;
	}

	/**
	 * 根据枚举的某些特点确定是哪个
	 * @param enumClass 枚举的类
	 * @param predicate 判断方法
	 * @param valueIfNotFound 如果未匹配成功返回什么
	 * @return 某个枚举值
	 * @param <E> 枚举
	 */
	public static <E extends Enum<E>> E from(Class<E> enumClass, Predicate<E> predicate, E valueIfNotFound) {
		return from(enumClass, predicate, Function.identity(), valueIfNotFound);
	}
	/**
	 * 根据枚举的某些特点确定是哪个
	 * @param enumClass 枚举的类
	 * @param predicate 判断方法
	 * @return 某个枚举值，未匹配则返回null
	 * @param <E> 枚举
	 */
	public static <E extends Enum<E>> E from(Class<E> enumClass, Predicate<E> predicate) {
		return from(enumClass, predicate, null);
	}
}
